﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Dycox.Reporting
{
    [TypeConverter(typeof(ElementUnitConverter))]
    public struct ElementUnit
    {

        public static readonly ElementUnit Empty = new ElementUnit();

        public ElementUnit(float value, ElementUnitType type)
        {
            _value = value;
            _type = type;
        }

        public ElementUnit(float value)
            : this(value, ElementUnitType.Literal)
        {

        }

        private float _value;

        public float Value
        {
            get { return _value; }
        }

        private ElementUnitType _type;

        public ElementUnitType Type
        {
            get { return _type; }
        }

        public bool IsEmpty
        {
            get
            {
                return _type == ElementUnitType.NotSet;
            }
        }

        public override string ToString()
        {
            switch (_type)
            {
                case ElementUnitType.Literal:
                    return _value.ToString();
                case ElementUnitType.Percentage:
                    return _value.ToString("p");
                default:
                    return base.ToString();
            }
        }

        public static ElementUnit Parse(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
                return ElementUnit.Empty;

            ElementUnitType type;

            text = text.Trim();
            int last = text.Length - 1;

            if (text[last] == '%')
            {
                type = ElementUnitType.Percentage;
                text = text.Substring(last);
            }
            else type = ElementUnitType.Literal;

            float value = float.Parse(text);

            if (type == ElementUnitType.Percentage) value /= 100f;

            return new ElementUnit(value, type);
        }

        /// <summary>
        /// Overrided. Determins whether current <see cref="ElementUnit"/> equals to another.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            ElementUnit other = (ElementUnit)obj;
            return this._type == other._type && this._value == other._value;
        }

        // override object.GetHashCode
        public override int GetHashCode()
        {
            return (int)_type ^ _value.GetHashCode();
        }

        class ElementUnitConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }

            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return base.CanConvertTo(context, destinationType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
            {
                if (value is string)
                {
                    string text = (string)value;
                    if (string.IsNullOrWhiteSpace(text))
                        return ElementUnit.Empty;

                    return ElementUnit.Parse(text);
                }
                return base.ConvertFrom(context, culture, value);
            }

            //public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
            //{
            //    if (destinationType == typeof(string))
            //    {
            //        return ((ElementUnit)value).ToString();
            //    }

            //    return base.ConvertTo(context, culture, value, destinationType);
            //}
        }
    }

    public enum ElementUnitType
    {
        NotSet,
        Literal,
        Percentage,
    }
}
